package ca.kooki.codesnippet.core;

import java.util.Hashtable;
import java.util.SortedSet;
import java.util.TreeSet;

public class TagCloud {

  //```````````````````````
  // MEMBER VARIABLES
  //```````````````````````
  
  private SortedSet<String> _sortedKeywords;
  private Hashtable<String,Integer> _keywordDensity;
  
  private int _minimum;
  private int _maximum;
  private int _distribution;
  private boolean _isStale;
  
  public enum Magnitude {
    Smallest,
    Small,
    Medium,
    Large,
    Largest
  }
  
  //```````````````````````
  // CONSTRUCTOR
  //```````````````````````
  
  public TagCloud()
  {
    init();
  }
  
  private void init()
  {
    _sortedKeywords = new TreeSet<String>();
    _keywordDensity = new Hashtable<String,Integer>();
    _isStale = true;
  }
  
  
  //```````````````````````
  // INTERFACE
  //```````````````````````
  
  public void addKeywords(String[] allKeywords)
  {
    _isStale = true;
    for (int i=0; i<allKeywords.length; i++)
    {
      String keyword = allKeywords[i];
      boolean isNew = addKeywordCount(keyword);
      
      if (isNew)
      {
        _sortedKeywords.add(keyword);  
      }
    }
  }
  
  public String[] getCloud()
  {
    return (String[])_sortedKeywords.toArray(new String[_sortedKeywords.size()]);
  }

  public TagCloud.Magnitude getMagnitudeOf(String keyword)
  {
    Integer count = _keywordDensity.get(keyword);
    if (count == null)
    {
      return TagCloud.Magnitude.Smallest;
    }
    updateDistributionAsRequired();
    
    int value = count.intValue();
    
    if (value == _minimum)
    {
      return TagCloud.Magnitude.Smallest;
    }
    else if (value == _maximum)
    {
      return TagCloud.Magnitude.Largest;
    }
    else if (value > (_minimum + 2*_distribution))
    {
      return TagCloud.Magnitude.Large;
    }
    else if (value > (_minimum + _distribution))
    {
      return TagCloud.Magnitude.Medium;
    }
    else
    {
      return TagCloud.Magnitude.Small;
    }
  }
  
  //```````````````````````
  // PRIVATE METHODS
  //```````````````````````
  
  private boolean addKeywordCount(String keyword)
  {
    Integer count = _keywordDensity.get(keyword);
    boolean isNew = count == null;
    count = isNew ? new Integer(1) : new Integer(count.intValue() + 1);
    _keywordDensity.put(keyword, count);
    return isNew;
  }

  private void updateDistributionAsRequired()
  {
    if (!_isStale)
    {
      return;
    }
    
    SortedSet<Integer> sortedCounts = new TreeSet<Integer>();
    sortedCounts.addAll(_keywordDensity.values());
    
    _minimum = sortedCounts.first().intValue();
    _maximum = sortedCounts.last().intValue();
    _distribution = (_maximum - _minimum) / 3;
  }
  
}
